// 用于通过 axi 协议配置temac ip核的参数


module axi_master_cfg#
(
    parameter 		TX_CFG                  = {24'b0,1'b0,7'b0101010},
    parameter 		RX_CFG                  = {24'b0,8'b00101010},
    parameter 		PAUSE_SRCAD_CFG	        = 48'h5af1f2f3f4f5,  	//暂停帧 mac源地址:48'h5af1f2f3f4f5,
    parameter 		SPEED_CFG	            = {30'b0,2'b10},
    parameter 		FLOW_CTRL_CFG	        = {30'b0,2'b00},
    parameter 		AD_FILTER_MODE_CFG      = {31'b0,1'b0},		//1'b1：启用混杂模式  1'b0：启用地址过滤模式,
    parameter 		UNICAST_AD_CFG          = 48'h0605040302DA,
    parameter       AD_TABLE0_CFG           = 48'h06050403020A,
    parameter       AD_TABLE1_CFG           = 48'h16151413121A,
    parameter       AD_TABLE2_CFG           = 48'h26252423222A,
    parameter       AD_TABLE3_CFG           = 48'h36353433323A,
    parameter       AD_TABLE4_CFG           = 48'h46454443424A,
    parameter       AD_TABLE5_CFG           = 48'h56555453525A,
    parameter       AD_TABLE6_CFG           = 48'h66656463626A,
    parameter       AD_TABLE7_CFG           = 48'h76757473727A,
    parameter       AD_TABLE8_CFG           = 48'h86858483828A,
    parameter       AD_TABLE9_CFG           = 48'h96959493929A,
    parameter       AD_TABLE10_CFG          = 48'hA6A5A4A3A2AA,
    parameter       AD_TABLE11_CFG          = 48'hB6B5B4B3B2BA,
    parameter       AD_TABLE12_CFG          = 48'hC6C5C4C3C2CA,
    parameter       AD_TABLE13_CFG          = 48'hD6D5D4D3D2DA,
    parameter       AD_TABLE14_CFG          = 48'hE6E5E4E3E2EA,
    parameter       AD_TABLE15_CFG          = 48'hF6F5F4F3F2FA,
    parameter       MDIO_CLK_CFG            = {25'b0,7'b1001001},  	// mdc = mAXI_aclk_i/(9+1)*2=50/20=2.5MHZ
    parameter       MDIO_WE1_DATA_CFG	    = {16'h0,16'h9340},		//PHY芯片地址：phy_A:5'b00010  phy_B:5'b00001   对PHY仅配置基本模式控制寄存器（0x00/5'h00）即可:双工/速度配置
    parameter       MDIO_WE1_CTRL_CFG	    = {19'b0,5'b00000,5'b00001,2'b01,1'b1},  //16'h9340： 千兆全双工 ； 16'hb300：百兆全双工；  16'h9300：十兆全双工
    parameter       MDIO_RD1_CTRL_CFG	    = {19'b0,5'b00000,5'b00001,2'b10,1'b1}   //16'h9240：千兆半双工（核不支持）；16'hb200：百兆半双工；  16'h9200：十兆半双工 
)
(
    input   wire    		init_axi_tx_i,      // 发起AXI事务
    output  wire    		axi_tx_done_o,      // AXI事务完成时断言

    // AXI 总线
    input   wire            m_axi_aclk_i,       // 输入的时钟信号
    input   wire            m_axi_a_reset_i,    // 异步复位信号
    output  wire    [7:0]   m_axi_awaddr_o,     // 写地址
    output  wire            m_axi_awvalid_o,    // 
    input   wire            m_axi_awready_i,    //
    output  wire    [31:0]  m_axi_wdata_o,      // axi 写出数据内容
    output  wire            m_axi_wvalid_o,     // 
    input   wire            m_axi_wready_i,
    input   wire    [1:0]   m_axi_bresp_i,
    input   wire            m_axi_bvalid_i,
    output  wire            m_axi_bready_o,
    output  wire    [7:0]   m_axi_araddr_o,
    output  wire            m_axi_arvalid_o,
    input   wire            m_axi_arready_i,
    input   wire    [31:0]  m_axi_rdata_i,
    input   wire    [1:0]   m_axi_rresp_i,
    input   wire            m_axi_rvalid_i,
    output  wire            m_axi_rready_o,
    
    
                                        
    output 			[6:0]	led_o,				// 输出led灯                

	input					uart_rx_i,			// 串口输入
    output					uart_tx_o			// 串口输出

);

    // 读写事务次数
    localparam WE_TRANSACTIONS_NUM  = 6'h2d;     // 比 #337行 case(write_index)最大值加1
    localparam RD_TRANSACTIONS_NUM  = 6'h13;     // 比 #530行 case(read_index) 最大值加1

    // 地址参数
    localparam TX_ADDRESS           = 8'h10;        // 发送器配置
    localparam RX_ADDRESS           = 8'h20;        // 接收器配置
    localparam PAUSE_SRC_AD0_ADDRESS    = 8'h30;    // 暂停源地址配置（字0）
    localparam PAUSE_SRC_AD1_ADDRESS    = 8'h40;    // 暂停源地址配置（字1）
    localparam SPEED_ADDRESS            = 8'h50;    // 速度配置 00=10Mbps  01=100Mbps   10=1Gbps
    localparam FLOW_CTRL_ADDRESS        = 8'h60;    // 流控配置 flow_ctrl_address[0] 发送流控使能，flow_ctrl_address[1] 接收器流控使能
    localparam AD_FILTER_MODE_ADDRESS   = 8'h70;    // 地址过滤模式  00 地址过滤，，01 不过滤
    localparam UNICAST_AD0_ADDRESS      = 8'h80;    // 单播地址（字0）
    localparam UNICAST_AD1_ADDRESS      = 8'h82;    // 单播地址（字1）
    localparam AD_TABLE0_ADDRESS        = 8'h84;    // 地址表配置（字0）
    localparam AD_TABLE1_ADDRESS        = 8'H86;    // 地址表配置（字1）
    localparam MDIO_CLK_ADDRESS         = 8'h90;    // MDIO 时钟配置 ClockDivide[5:0], [6] = MDIO 使能
    localparam MDIO_CTRL_ADDRESS        = 8'hA0;    // MDIO 控制配置
    localparam MDIO_RD_DATA_ADDRESS     = 8'hB0;    // MDIO 读数据
    localparam MDIO_WE_DATA_ADDRESS     = 8'hC0;    // MDIO 写数据


    parameter   [1:0]   IDLE            = 2'b00;    // 当INIT_AXI_TXN上有0到1的转换时，当前状态机跳转为INIT_WRITE，INIT_WRITE此状态启动AXI4Lite写事务
    parameter   [1:0]   INIT_WRITE      = 2'b01;    // 此状态初始化写事务，一旦完成写，状态机将状态更改为INIT_READ
    parameter   [1:0]   INIT_READ       = 2'b10;    // 此状态初始化读取事务，读取完成


    // AXI 总线 8 个 输出信号寄存器
    reg         [7:0]   axi_awaddr_r;               // output
    reg                 axi_awvalid_r;              // output
    reg         [31:0]  axi_wdata_r;                // output
    reg                 axi_wvalid_r;               // output
    reg                 axi_bready_r;               // output
    reg         [7:0]   axi_araddr_r;               // output
    reg                 axi_arvalid_r;              // output
    reg                 axi_rready_r;               // output


    // 中间信号
    reg         [1:0]   master_state_r;             // 
    reg                 init_txn_ff_r;              // 用于产生一个脉冲，开启AXI事务
    reg                 init_txn_ff2_r;             // 用于产生一个脉冲，开启AXI事务
    reg                 start_single_write_r;
    reg         [5:0]   write_index_r;
    reg                 start_single_read_r;
    reg         [5:0]   read_index_r;
    reg                 write_issued_r;
    reg                 read_issued_r;
    reg                 last_write_r;
    reg                 last_read_r;
    reg                 writes_done_r;
    reg                 reads_done_r;
    reg                 axi_tx_done_r;
    reg         [31:0]  rd_data_val_r;

    // AXI 总线 8 个 输出信号寄存器
    assign m_axi_awaddr_o       = axi_awaddr_r;         
    assign m_axi_awvalid_o      = axi_awvalid_r;         
    assign m_axi_wdata_o        = axi_wdata_r;             
    assign m_axi_wvalid_o       = axi_wvalid_r;           
    assign m_axi_bready_o       = axi_bready_r;           
    assign m_axi_araddr_o       = axi_araddr_r;           
    assign m_axi_arvalid_o      = axi_arvalid_r;         
    assign m_axi_rready_o       = axi_rready_r;           
    assign axi_tx_done_o        = axi_tx_done_r;
    
    
    
    
    
    reg			[159:0]			uart_print_data;
    reg			[31:0]			uart_print_data_len;
    reg							uart_print_en;
    wire						uart_print_finish;
    uart_block uart_block_blk(
        .sysclk_i(m_axi_aclk_i),   					// 时钟输入
        .reset_i(reset_i),     				    	// 复位输入
        .uart_rx_i(uart_rx_i),   					// UART 输入
        
        .uart_print_data(uart_print_data),        	// 待打印的文本
        .uart_print_data_len(uart_print_data_len),	// 待打印文本有效长度
        .uart_print_en(uart_print_en) ,           	// 打印启用有效位
        .uart_print_finish(uart_print_finish),  	// 打印完成有效位
        .uart_tx_o(uart_tx_o));

    
    
    reg 		[6:0] 	led_r		= 	7'b0;
    assign				led_o 		= 	led_r;
    
    // 检测 done 是否完成
    always @(posedge m_axi_aclk_i) begin
    	if(init_txn_pulse == 1'b1) begin
        	uart_print_data <= "pulse == 1;";
            uart_print_data_len <= 11;
            uart_print_en <= 1'b1;
            led_r <= 1'b1;
        end 
        else begin
	        uart_print_en <= 1'b0;
        end
    end

    // 产生一个 脉冲 以启动 AXI 事务
    always @(posedge m_axi_aclk_i) begin

        if (m_axi_a_reset_i == 1) begin
            init_txn_ff_r <= 1'b0;
            init_txn_ff2_r <= 1'b0;
        end
        else begin
            init_txn_ff_r <= init_axi_tx_i;
            init_txn_ff2_r = init_txn_ff_r;
        end
    end  
	// init_txn_ff2 = 1， init_txn_ff = 1，  =>  init_txn_pulse = 0
	// init_txn_ff2 = 0， init_txn_ff = 1，  =>  init_txn_pulse = 1
	// init_txn_ff2 = 1， init_txn_ff = 0，  =>  init_txn_pulse = 0
	// init_txn_ff2 = 0， init_txn_ff = 0，  =>  init_txn_pulse = 0
	// 这里会使 init_txn_pulse 产生一个时钟的激活信号
    assign init_txn_pulse       = (!init_txn_ff2_r) && init_txn_ff_r;



    // 写地址通道
    always @(posedge m_axi_aclk_i) begin
        // 复位
        if(m_axi_a_reset_i == 1 || init_axi_tx_i == 1) begin
            axi_awvalid_r <= 1'b0;
        end


        // 用户逻辑可用新地址/数据命令
        else begin

            if(start_single_write_r) begin
                axi_awvalid_r <= 1'b1;
            end

            // 地址由互联从机接收（从机发出 m_axi_awready_i ）
            else if (m_axi_awready_i && axi_awvalid_r) begin
                axi_awvalid_r <= 1'b0;
            end
        end

    end


    // write_index是一个计数器，用于跟踪 已发出/已启动 的写事务的数量         
    always @(posedge m_axi_aclk_i) begin
        
        if (m_axi_a_reset_i == 1 || init_txn_pulse == 1) begin
            write_index_r <= 0;
        end

        else if (start_single_write_r) begin
            write_index_r <= write_index_r + 1;
        end

    end


    // 写数据通道：axi_wvalid信号
    always @(posedge m_axi_aclk_i) begin
        if (m_axi_a_reset_i == 1 || init_txn_pulse == 1) begin
            axi_wvalid_r <= 1'b0;
        end
        //通过用户逻辑给新的地址/数据命令发送信号         
        else if (start_single_write_r) begin
            axi_wvalid_r <= 1'b1;
        end
        //数据被互连从设备接受（从设备发出m_axi_wready）    
        else if (m_axi_wready_i && axi_wvalid_r) begin
            axi_wvalid_r <= 1'b0;
        end
    end


    // 根据需要针对不同的地址模式修改它们。
    always @(posedge m_axi_aclk_i) begin
        if (m_axi_a_reset_i == 1 || init_txn_pulse == 1'b1) begin
            axi_awaddr_r <= SPEED_ADDRESS;
            axi_wdata_r <= SPEED_CFG;
        end
        else if(m_axi_bvalid_i) begin
            case (write_index_r)
                6'h01: begin
                    axi_awaddr_r <= TX_ADDRESS;
                    axi_wdata_r <= TX_CFG;
                end

                6'h02:  begin
                    axi_awaddr_r <= RX_ADDRESS; 
                    axi_wdata_r  <= RX_CFG; 
                end
                6'h03:  begin
                    axi_awaddr_r <= PAUSE_SRC_AD0_ADDRESS; 
                    axi_wdata_r  <= PAUSE_SRCAD_CFG[31:0]; 
                end
                6'h04:  begin
                    axi_awaddr_r <= PAUSE_SRC_AD1_ADDRESS; 
                    axi_wdata_r  <= {16'h0, PAUSE_SRCAD_CFG[47:32]}; 
                end
                6'h05:  begin
                    axi_awaddr_r <= FLOW_CTRL_ADDRESS; 
                    axi_wdata_r  <= FLOW_CTRL_CFG; 
                end
                6'h06:  begin
                    axi_awaddr_r <= AD_FILTER_MODE_ADDRESS; 
                    axi_wdata_r  <= AD_FILTER_MODE_CFG; 
                end
                6'h07:  begin
                    axi_awaddr_r <= UNICAST_AD0_ADDRESS; 
                    axi_wdata_r  <= UNICAST_AD_CFG[31:0]; 
                end
                6'h08:  begin
                    axi_awaddr_r <= UNICAST_AD1_ADDRESS; 
                    axi_wdata_r  <= {16'h0,UNICAST_AD_CFG[47:32]}; 
                end
				6'h09:  begin
                    axi_awaddr_r <= AD_TABLE1_ADDRESS; 
                    axi_wdata_r  <= {16'hf, AD_TABLE15_CFG[47:32]}; 
                end
                6'h0A:  begin
                    axi_awaddr_r <= AD_TABLE0_ADDRESS; 
                    axi_wdata_r  <= AD_TABLE15_CFG[31:0]; 
                end
                6'h0B:  begin
                    axi_awaddr_r <= AD_TABLE1_ADDRESS; 
                    axi_wdata_r  <= {16'he,AD_TABLE14_CFG[47:32]}; 
                end
                6'h0C:  begin
                    axi_awaddr_r <= AD_TABLE0_ADDRESS; 
                    axi_wdata_r  <= AD_TABLE14_CFG[31:0]; 
                end
				6'h0D:  begin
                    axi_awaddr_r <= AD_TABLE1_ADDRESS; 
                    axi_wdata_r  <= {16'hd,AD_TABLE13_CFG[47:32]}; 
                end
                6'h0E:  begin
                    axi_awaddr_r <= AD_TABLE0_ADDRESS; 
                    axi_wdata_r  <= AD_TABLE13_CFG[31:0]; 
                end
				6'h0F:  begin
                    axi_awaddr_r <= AD_TABLE1_ADDRESS; 
                    axi_wdata_r  <= {16'hc,AD_TABLE12_CFG[47:32]}; 
                end
                6'h10:  begin
                    axi_awaddr_r <= AD_TABLE0_ADDRESS; 
                    axi_wdata_r  <= AD_TABLE12_CFG[31:0]; 
                end
                6'h11:  begin
                    axi_awaddr_r <= AD_TABLE1_ADDRESS; 
                    axi_wdata_r  <= {16'hb,AD_TABLE11_CFG[47:32]}; 
                end
                6'h12:  begin
                    axi_awaddr_r <= AD_TABLE0_ADDRESS; 
                    axi_wdata_r  <= AD_TABLE11_CFG[31:0]; 
                end
                6'h13:  begin
                    axi_awaddr_r <= AD_TABLE1_ADDRESS; 
                    axi_wdata_r  <= {16'ha,AD_TABLE10_CFG[47:32]}; 
                end
                6'h14:  begin
                    axi_awaddr_r <= AD_TABLE0_ADDRESS; 
                    axi_wdata_r  <= AD_TABLE10_CFG[31:0]; 
                end
				6'h15:  begin
                    axi_awaddr_r <= AD_TABLE1_ADDRESS; 
                    axi_wdata_r  <= {16'h9,AD_TABLE9_CFG[47:32]}; 
                end
                6'h16:  begin
                    axi_awaddr_r <= AD_TABLE0_ADDRESS; 
                    axi_wdata_r  <= AD_TABLE9_CFG[31:0]; 
                end
				6'h17:  begin
                    axi_awaddr_r <= AD_TABLE1_ADDRESS; 
                    axi_wdata_r  <= {16'h8,AD_TABLE8_CFG[47:32]}; 
                end
                6'h18:  begin
                    axi_awaddr_r <= AD_TABLE0_ADDRESS; 
                    axi_wdata_r  <= AD_TABLE8_CFG[31:0]; 
                end
                6'h19:  begin
                    axi_awaddr_r <= AD_TABLE1_ADDRESS; 
                    axi_wdata_r  <= {16'h7,AD_TABLE7_CFG[47:32]}; 
                end
                6'h1A:  begin
                    axi_awaddr_r <= AD_TABLE0_ADDRESS; 
                    axi_wdata_r  <= AD_TABLE7_CFG[31:0]; 
                end
                6'h1B:  begin
                    axi_awaddr_r <= AD_TABLE1_ADDRESS; 
                    axi_wdata_r  <= {16'h6,AD_TABLE6_CFG[47:32]}; 
                end
                6'h1C:  begin
                    axi_awaddr_r <= AD_TABLE0_ADDRESS; 
                    axi_wdata_r  <= AD_TABLE6_CFG[31:0]; 
                end
				6'h1D:  begin
                    axi_awaddr_r <= AD_TABLE1_ADDRESS; 
                    axi_wdata_r  <= {16'h5,AD_TABLE5_CFG[47:32]}; 
                end
                6'h1E:  begin
                    axi_awaddr_r <= AD_TABLE0_ADDRESS; 
                    axi_wdata_r  <= AD_TABLE5_CFG[31:0]; 
                end
				6'h1F:  begin
                    axi_awaddr_r <= AD_TABLE1_ADDRESS; 
                    axi_wdata_r  <= {16'h4,AD_TABLE4_CFG[47:32]}; 
                end
                6'h20:  begin
                    axi_awaddr_r <= AD_TABLE0_ADDRESS; 
                    axi_wdata_r  <= AD_TABLE4_CFG[31:0]; 
                end
                6'h21:  begin
                    axi_awaddr_r <= AD_TABLE1_ADDRESS; 
                    axi_wdata_r  <= {16'h3,AD_TABLE3_CFG[47:32]}; 
                end
                6'h22:  begin
                    axi_awaddr_r <= AD_TABLE0_ADDRESS; 
                    axi_wdata_r  <= AD_TABLE3_CFG[31:0]; 
                end
                6'h23:  begin
                    axi_awaddr_r <= AD_TABLE1_ADDRESS; 
                    axi_wdata_r  <= {16'h2,AD_TABLE2_CFG[47:32]}; 
                end
                6'h24:  begin
                    axi_awaddr_r <= AD_TABLE0_ADDRESS; 
                    axi_wdata_r  <= AD_TABLE2_CFG[31:0]; 
                end
				6'h25:  begin
                    axi_awaddr_r <= AD_TABLE1_ADDRESS; 
                    axi_wdata_r  <= {16'h1,AD_TABLE1_CFG[47:32]}; 
                end
                6'h26:  begin
                    axi_awaddr_r <= AD_TABLE0_ADDRESS; 
                    axi_wdata_r  <= AD_TABLE1_CFG[31:0]; 
                end
				6'h27:  begin
                    axi_awaddr_r <= AD_TABLE1_ADDRESS; 
                    axi_wdata_r  <= {16'h0,AD_TABLE0_CFG[47:32]}; 
                end   
                6'h28:  begin
                    axi_awaddr_r <= AD_TABLE0_ADDRESS; 
                    axi_wdata_r  <= AD_TABLE0_CFG[31:0]; 
                end
                    
                6'h29:  begin
                    axi_awaddr_r <= MDIO_CLK_ADDRESS; 
                    axi_wdata_r  <= MDIO_CLK_CFG; 
                end
                6'h2A:  begin
                    axi_awaddr_r <= MDIO_WE_DATA_ADDRESS; 
                    axi_wdata_r  <= MDIO_WE1_DATA_CFG; 
                end
				6'h2B:  begin
                    axi_awaddr_r <= MDIO_CTRL_ADDRESS; 
                    axi_wdata_r  <= MDIO_WE1_CTRL_CFG; 
                end
                6'h2C:  begin                        //读启动
                    axi_awaddr_r <= MDIO_CTRL_ADDRESS; 
                    axi_wdata_r  <= MDIO_RD1_CTRL_CFG; 
                end
				default: begin
                    axi_awaddr_r <= 8'h0; 
                    axi_wdata_r  <= 32'h0; 
                end
            endcase
        end
    end

    // 写响应（b）通道
    always @(posedge m_axi_aclk_i) begin
        if (m_axi_a_reset_i == 1 || init_txn_pulse == 1'b1) begin
            axi_bready_r <= 1'b0;
        end

        // 由主控器接受/确认带有axi_bready的信号灯，从机断言m_axi_bvalid
        else if (m_axi_awready_i && m_axi_wready_i) begin
            axi_bready_r <= 1'b1;
        end

        // 一个时钟周期后置低       
        else if (m_axi_bvalid_i) begin
            axi_bready_r <= 1'b0;
        end
        else begin
            axi_bready_r <= axi_bready_r;
        end
    end



    // 读时序
    always @(posedge m_axi_aclk_i) begin
        if (m_axi_a_reset_i == 1 || init_txn_pulse == 1'b1) begin
            read_index_r <= 0;
        end
        else if (start_single_read_r) begin
            read_index_r <= read_index_r + 1;
        end
    end


    // 当主机有一个有效的读取地址时，将声明一个新的axi_arvalid。  
    always @(posedge m_axi_aclk_i) begin
        if (m_axi_a_reset_i == 1 || init_txn_pulse == 1'b1) begin
            axi_arvalid_r <= 1'b0;
        end
        // 表示用户逻辑可用新的读地址命令            
        else if (start_single_read_r) begin
            axi_arvalid_r <= 1'b1;
        end
        else if (m_axi_arready_i && axi_arvalid_r) begin
            axi_arvalid_r <= 1'b0;
        end
    end


    // 读数据通道
    always @(posedge m_axi_aclk_i) begin
        if (m_axi_a_reset_i == 1 || init_txn_pulse == 1'b1) begin
            axi_rready_r <= 1'b0;
        end
        else if (m_axi_arready_i) begin
            axi_rready_r <= 1'b1;
        end
        else if (m_axi_rvalid_i) begin
            axi_rready_r <= 1'b0;
        end
    end

    // 根据需要针对不同的地址模式修改它们。

                                          
    //read addresses                                              
    always @(posedge m_axi_aclk_i) begin                                                     
        if (m_axi_a_reset_i == 1  || init_txn_pulse == 1'b1) begin                                                 
            axi_araddr_r <= SPEED_ADDRESS;
        end                                                   
            // 表示新的写地址/写数据,可由用户逻辑提供                            
        //else if (m_axi_arready && axi_arvalid)
        else if (m_axi_rvalid_i && axi_rready_r) begin
            case(read_index_r)
                //6'h00:  axi_araddr <= speed_address;
                6'h01:  axi_araddr_r <= TX_ADDRESS;
                6'h02:  axi_araddr_r <= RX_ADDRESS;
                6'h03:  axi_araddr_r <= PAUSE_SRC_AD0_ADDRESS;
                6'h04:  axi_araddr_r <= PAUSE_SRC_AD1_ADDRESS;
                6'h05:  axi_araddr_r <= FLOW_CTRL_ADDRESS;
                6'h06:  axi_araddr_r <= AD_FILTER_MODE_ADDRESS;
                6'h07:  axi_araddr_r <= UNICAST_AD0_ADDRESS;
                6'h08:  axi_araddr_r <= UNICAST_AD1_ADDRESS;
                6'h09:  axi_araddr_r <= AD_TABLE1_ADDRESS;  //读出为最近配置地址表的地址
                6'h0A:  axi_araddr_r <= AD_TABLE0_ADDRESS;
                6'h0B:  axi_araddr_r <= AD_TABLE1_ADDRESS;
                6'h0C:  axi_araddr_r <= AD_TABLE0_ADDRESS;
                6'h0D:  axi_araddr_r <= AD_TABLE1_ADDRESS;
                6'h0E:  axi_araddr_r <= AD_TABLE0_ADDRESS;
                6'h0F:  axi_araddr_r <= AD_TABLE1_ADDRESS; 
                6'h10:  axi_araddr_r <= AD_TABLE0_ADDRESS;
                6'h11:  axi_araddr_r <= MDIO_CLK_ADDRESS; 
                6'h12:  axi_araddr_r <= MDIO_RD_DATA_ADDRESS; 

                default: axi_araddr_r <= 8'h0; 
            endcase    
        end                                                   
    end      


    always @(posedge m_axi_aclk_i) begin
        if (m_axi_a_reset_i == 1 || init_txn_pulse == 1'b1) begin
            rd_data_val_r <= 32'h0;
        end

        // 读取有效之后，将数据放到 rd_data_val_r 中
        else if (m_axi_rvalid_i && axi_rready_r) begin
            rd_data_val_r <= m_axi_rdata_i;
        end
    end


    // 状态机实现
    always @(posedge m_axi_aclk_i) begin
        if (m_axi_a_reset_i == 1) begin
            master_state_r              <= IDLE;
            start_single_write_r        <= 1'b0;
            write_issued_r              <= 1'b0;
            start_single_read_r         <= 1'b0;
            read_issued_r               <= 1'b0;
            axi_tx_done_r               <= 1'b0;
        end

        else begin
            case (master_state_r)
                IDLE: begin
                    // 声明 init_txn_pulse 时，此状态负责启动 axi事务 
                    if (init_txn_pulse) begin
                        master_state_r  <= INIT_WRITE;
                        axi_tx_done_r <= 1'b0;
                    end 
                    else begin
                        master_state_r <= IDLE;
                    end
                end

                INIT_WRITE: begin
                    // 此状态负责发出 start_single_write 脉冲以启动写入事务。  
                    // 发出写事务，直到断言last_write信号为止。  
                    // 写控制器    
                    if (writes_done_r) begin
                        master_state_r <= INIT_READ;
                    end
                    else begin
                        master_state_r <= INIT_WRITE;
                        if (~ axi_awvalid_r         
                            && ~ axi_wvalid_r       
                            && ~ m_axi_bvalid_i 
                            && ~ m_axi_bready_o 
                            && ~ last_write_r 
                            && ~ start_single_write_r 
                            && ~ write_issued_r) begin   

                            // 开始写 axi ， start_single_write 置 1                                                         
                            start_single_write_r <= 1'b1;                                   
                            write_issued_r  <= 1'b1;                                        
                        end                                                             

                        // 如果正在写，那么 
                        else if (m_axi_bvalid_i) begin                                                           
                            write_issued_r  <= 1'b0;                                        
                        end                                                             
                        else begin                                                           
                            start_single_write_r <= 1'b0; //negate to generate a pulse      
                        end   
                    end
                end

                INIT_READ:                                                                
	            // 此状态负责发出start_single_read脉冲以启动读取事务。  
                // 发出读事务，直到断言last_read信号为止。                           
	            // read controller                                                     
                    if (reads_done_r) begin                                                                
                        master_state_r      <= IDLE;
                        axi_tx_done_r       <= 1'b1;
                    end                                                                  
                    else begin                                                                
                        master_state_r  <= INIT_READ;                                      
                                                                                        
                        if (~axi_arvalid_r
                            && ~m_axi_rvalid_i
                            && ~axi_rready_r 
                            && ~last_read_r 
                            && ~start_single_read_r
                            && ~read_issued_r )
                        begin                                                            
                            start_single_read_r <= 1'b1;                                     
                            read_issued_r  <= 1'b1;                                          
                        end      
                        else if (m_axi_rvalid_i) begin                                                            
                            read_issued_r  <= 1'b0;                                          
                        end                                                              
                        else begin                                                            
                            start_single_read_r <= 1'b0; //negate to generate a pulse        
                        end                                                              
                    end       

                default: begin
                    master_state_r  <= IDLE;        
                end

            endcase
        end
    end



    //终端写入次数                                                                           
	always @(posedge m_axi_aclk_i) begin                                                                             
	    if (m_axi_a_reset_i == 1  || init_txn_pulse == 1'b1) begin                                                      
	      	last_write_r <= 1'b0;    
        end

        //最后一次写入应与写入地址就绪响应相关联       
	    else if ((write_index_r == WE_TRANSACTIONS_NUM) && m_axi_awready_i)    //transactions_num值比 case(write_index)值加1            
	      	last_write_r <= 1'b1;                                                           
	    else                                                                            
	      	last_write_r <= last_write_r;                                                     
	end       


    //检查最后的写入完成。                                                
	//此逻辑是用最后的写入响应来限定最后的写入计数。 这演示了如何确认是否已提交写入。                                                                      
	always @(posedge m_axi_aclk_i) begin                                                                             
	    if (m_axi_a_reset_i == 1  || init_txn_pulse == 1'b1)                                                         
	      	writes_done_r <= 1'b0;                                                                                                                                     
	      	//the writes_done should be associated with a bready response                 
	    else if (last_write_r && m_axi_bvalid_i && axi_bready_r)                              
	      	writes_done_r <= 1'b1;                                                          
	    else                                                                            
	      	writes_done_r <= writes_done_r;                                                   
	end     


    //检查最后的写入完成。                                                
	//此逻辑是用最后的写入响应来限定最后的写入计数。 这演示了如何确认是否已提交写入。                                                                      
	always @(posedge m_axi_aclk_i) begin                                                                             
	    if (m_axi_a_reset_i == 1  || init_txn_pulse == 1'b1)                                                         
	      	reads_done_r <= 1'b0;                                                                                                                                       
	    //reads_done应该与已读响应相关联                
	    else if (last_read_r && m_axi_rvalid_i && axi_rready_r)                               
	      	reads_done_r <= 1'b1;                                                           
	    else                                                                            
	      	reads_done_r <= reads_done_r;                                                      
	end                         

endmodule
